package Finance::NSCC::Insurance::File::POV;

use Moose;
extends 'Finance::NSCC::Insurance::File';
use Finance::NSCC::Insurance::Utils qw/trim/;

our $VERSION = '0.001000';

our $RHEADER = qr/^[CB]10(.{4})POV.{4}(.{8}).{6}.{12}(.{12}).{8}(.)(.{10}).{229}$/;
our $R12 = qr/^[CB]12(.{4})(.{4})(.{10})(.{10})(?:PVF|PNF|PFF)INA.{263}$/;
our $R1301 = qr/^[CB]1301(.{30})(.{9})(..)(.{20})(..)(.{30})(.{30})(.{30})(.{4})(.{3})(.{10})(.{10}).(..)(.)(..)(.).{108}$/;
our $R1302 = qr/^[CB]1302(.{30})(.{16})(.{3}).(.{16})(.{3}).(.{16})(.{3}).(.{16})(.{3}).(.{16})(.{3}).{166}$/;
our $R1303 = qr/^[CB]1303(.{30})(.{9})(.{5})(.{5})(.{16})(.{10})(.{18})(.{10})(.{40})(.{3})(.{9})(.).{139}$/;
our $R1304 = qr/^[CB]1304(.{30})(.{9})(.{5})(.{5})(.{8})(.{8})(.{8})(.{10})(..)(.{18})(..)(.{10})(.{16}).{164}$/;
our $R1305 = qr/^[CB]1305(.{30})(.{20})(..)(..)((.{35})(.{25})(.{25})(.{10})(.{10}))(.{20})(.)(.{10}).{105}$/;
our $R1306 = qr/^[CB]1306(.{30})(.{8})(.{3}).(.{8})(.{3}).(.{8})(.{3}).(.{8})(.{3}).(.{8})(.{3}).{206}$/;
our $R1307 = qr/^[CB]1307(.{30})(.{3})(.{16})(.{3})(.).(.{3})(.{16})(.{3})(.).(.{3})(.{16})(.{3})(.).(.{3})(.{16})(.{3})(.).(.{3})(.{16})(.{3})(.).{146}$/;
our $R1308 = qr/^[CB]1308(.{30})(.{16})(.{3})(.{3})(..)(.)(.)(.{4})(.{10})(.{10})(.)(.)(.{10})(.)(.{10})(.{16})(..)(.{3})(..)(..)(..)(.).{164}$/;
our $R1309 = qr/^[CB]1309(.{30})((.{35})(.{25})(.{25})(.{10})(.{10}))(..)(.{20})(..)(.{8})(.{3})(.)(.)(.).{122}$/;
our $R1310 = qr/^[CB]1310(.{30})(..)(.{35})(.{35})(.{30})(..)(.{15})(...).{143}$/;
our $R1311 = qr/^[CB]1311(.{30})(.{4})(.{35})(.{14})(.{4})(.{8})(.{8})(..)(.{14})(.{10}).{166}$/;


sub _build_records {
  my $self = shift;
  my $io = $self->_file_handle;

  my $record_count = 1;         #header is already processed
  my @records;
  my $line = $io->getline or $self->_error("Premature end before C12 record.");
  $record_count++;
  #CONTRA
  if ( $line !~ /$R12/ ) {
    $self->_error("'$line' where C12 record expected.");
  }

  defined($line = $io->getline) or $self->_error("Premature end on C12 record.");
  $record_count++;
  #contracts loop
  while (my (@m01) = map{ trim $_} ($line =~ /$R1301/)) {
    my $contract_num = $m01[0];
    my $contract = {
                    nscc_num           => $self->nscc_num,
                    contract_num       => $contract_num,
                    cusip              => $m01[1],
                    carrier_company_id => $self->carrier_company_id,
                    irs_q_code         => $m01[8],
                   };
    push(@records, $contract);

    if ($m01[4]) {
      $contract->{erc_id}   = $m01[3];
      $contract->{erc_id_q} = $m01[4];
    }
    $contract->{group_num}      = $m01[5] if $m01[5];
    $contract->{original_contract_num} = $m01[6] if $m01[6];
    $contract->{dist_acct_num}  = $m01[7]  if $m01[7];
    $contract->{prod_type_code} = $m01[9]  if $m01[9];
    $contract->{comm_opt}       = $m01[10] if $m01[10];
    $contract->{comm_ext}       = $m01[11] if $m01[11];
    $contract->{contract_state} = $m01[12] if $m01[12];
    if ($m01[13]) {
      $contract->{fund_tfr_rest_i}      = $m01[13];
      $contract->{fund_tfr_rest_reason} = $m01[14];
    }
    $contract->{agent_authz_i} = $m01[15] if $m01[15];

    defined($line = $io->getline) && $record_count++;
    while (my (@m02) = map{ trim $_} ($line =~/$R1302/)) {
      $record_count++;
      $contract->{valuations} ||= [];
      my @valuations =
        map{ {value_amt => ($m02[1] / 100), value_q => $m02[2]} }
          grep{ $_->[1] }
            ([@m02[1,2]], [@m02[3,4]], [@m02[5,6]], [@m02[7,8]], [@m02[9,10]]);
      push(@{$contract->{valuations}}, @valuations);
      defined($line = $io->getline) && $record_count++;
    }
    while (my (@m03) = map{ trim $_} ($line =~/$R1303/)) {
      $record_count++;
      $contract->{underlying_assets} ||= [];
      my $asset = {
                   cusip       => $m03[1],
                   fund_id     => $m03[2],
                   sub_fund_id => $m03[3],
                  };
      push(@{$contract->{underlying_assets}}, $asset);
      $asset->{fund_value} = $m03[4] if $m03[4] * 1;
      $asset->{fund_pct}   = $m03[5] if $m03[5] * 1;
      $asset->{fund_units} = $m03[6] if $m03[6] * 1;
      $asset->{fund_guaranteed_interest_rate} = $m03[7] if $m03[7] * 1;
      $asset->{fund_name}   = $m03[8]  if $m03[8];
      $asset->{fund_type}   = $m03[9]  if $m03[9];
      $asset->{fund_cusip}  = $m03[10] if $m03[10];
      $asset->{fund_rest_i} = $m03[11] if $m03[11];
      defined($line = $io->getline) && $record_count++;

      while (my (@m04) = map{ trim $_} ($line =~/$R1304/)) {
        $asset->{guarantees} ||= [];
        my $guarantee = {};
        push(@{$asset->{guarantees}}, $guarantee);

        if ($m04[4]) {
          $guarantee->{start_d} = $m04[4];
          $guarantee->{start_d} =~ s/(....)(..)(..)/$1-$2-$3/;
        }
        if ($m04[5]) {
          $guarantee->{end_d} = $m04[5];
          $guarantee->{end_d} =~ s/(....)(..)(..)/$1-$2-$3/;
        }
        if ($m04[6]) {
          $guarantee->{maturity_d} = $m04[6];
          $guarantee->{maturity_d} =~ s/(....)(..)(..)/$1-$2-$3/;
        }
        if ($m04[8]) {
          $guarantee->{rate}      = $m04[7];
          $guarantee->{rate_type} = $m04[8];
        }
        $guarantee->{units} = $m04[9] * 1 if $m04[9];
        if ($m04[10]) {
          $guarantee->{period_freq_code} = $m04[10];
          $guarantee->{period_num}       = $m04[11];
        }
        $guarantee->{value} = $m04[12] * 1 if $m04[12];
        defined($line = $io->getline) && $record_count++;
      }
    }
    while (my (@m05) = map{ trim $_} ($line =~/$R1305/)) {
      $contract->{agents} ||= [];
      my $agent = {
                   role      => $m05[3],
                   entity_i  => $m05[11] eq 'X' ? 1 : 0,
                  };
      push(@{$contract->{agent}}, $agent);

      if ($m05[1]) {
        $agent->{tax_id}     = $m05[1];
        $agent->{'tax_id_q'} = $m05[2];
      }
      #natural/non-natural section
      if ($agent->{entity_i}) {
        $agent->{entity_name} = $m05[4];
      } else {
        $agent->{last_name}   = $m05[5];
        $agent->{first_name}  = $m05[6] if $m05[6];
        $agent->{middle_name} = $m05[7] if $m05[7];
        $agent->{prefix}      = $m05[8] if $m05[8];
        $agent->{suffix}      = $m05[9] if $m05[9];
      }
      $agent->{brokers_id} = $m05[10] if $m05[10];
      $agent->{national_producer_num} = $m05[12] if $m05[12];

      defined($line = $io->getline) && $record_count++;
    }
    if (my (@m06) = map{ trim $_} ($line =~/$R1306/)) {
      #create date records from date1, date2, etc
      my @dates = map { { date_v => $_->[0], 'date_q' => $_->[1] } }
        map { $_->[0] =~ s/(....)(..)(..)/$1-$2-$3/; $_ }
          grep { $_->[0] =~ /^\d{8}$/ && $_->[1] }
            ([@m06[1,2]],[@m06[3,4]],[@m06[5,6]],[@m06[7,8]],[@m06[9,10]]);

      $contract->{dates} = \@dates;
      defined($line = $io->getline) && $record_count++;
    }
    while (my (@m07) = map{ trim $_} ($line =~/$R1307/)) {
      $contract->{events} ||= [];
      #create event records from date1, date2, etc
      my @events = map {
        +{
          period_type_code => $_->[0],
          total_amt        => $_->[1] / 100,
          event_type_code  => $_->[2],
          gross_net_i      => $_->[3],
         }
      } grep { $_->[0] }
        ([@m07[1..4]],[@m07[5..8]],[@m07[9..12]],[@m07[13..16]],[@m07[17..20]]);

      push(@{$contract->{events}}, @events);
      defined($line = $io->getline) && $record_count++;
    }
    while (my (@m08) = map{ trim $_} ($line =~/$R1308/)) {
      #TODO
      $contract->{annuitization_payouts} ||= [];
      my $payout = {
                    annuity_payout_amt   => $m08[1] / 100,
                    annuity_payout_amt_q => $m08[2],
                    annuity_freq_code    => $m08[3],
                    payout_opt           => $m08[4],
                    payout_type          => $m08[6],
                   };
      push(@{$contract->{annuitization_payouts}}, $payout);

      $payout->{lives_type}     = $m08[5] if $m08[5];
      $payout->{certain_period} = $m08[7] if $m08[7] * 1;
      $payout->{increase_pct}          = ($m08[8] / (10 ** 9)) if $m08[8] * 1;
      $payout->{assumed_interest_rate} = ($m08[9] / (10 ** 9)) if $m08[9] * 1;

      if ($m08[10]) {
        $payout->{levelization_i} = $m08[10] eq 'Y' ? 1 : 0;
      }
      $payout->{primary_survivor_adj_type} =  $m08[11] if $m08[11];
      $payout->{primary_survivor_adj_pct}  = ($m08[12] / (10 ** 9)) if $m08[12];
      $payout->{joint_survivor_adj_type}   =  $m08[13] if $m08[13];
      $payout->{joint_survivor_adj_pct}    = ($m08[14] / (10 ** 9)) if $m08[14];

      if ($m08[16]) {
        $payout->{exclusion_i} = $m08[16];
        #XXX TODO
        if ( $m08[16] eq '') {
          $payout->{exclusion_value_dollar} = $m08[15] / (10 ** 2);
        } else {
          $payout->{exclusion_value_pct} = $m08[15] / (10 ** 15);
        }
      }

      $payout->{certain_period_q} = $m08[17] if $m08[17];
      $payout->{liquidity_opt   } = $m08[18] if $m08[18];
      $payout->{liquidity_waiting_period} = $m08[19] if $m08[19];
      $payout->{liquidity_trigger_event}  = $m08[20] if $m08[20];

      if ($m08[21]) {
        $payout->{liquidity_partial} = $m08[21] eq 'Y' ? 1 : 0;
      }

      defined($line = $io->getline) && $record_count++;
    }
    while ( my (@m09) = map{ trim $_} ($line =~ /$R1309/)) {
      $contract->{parties} ||= []; #new arrayref if blank
      my $party = {
                   role      => $m09[7],
                   entity_i  => $m09[12] eq 'X' ? 1 : 0,
                   type_code => $m09[13],
                  };
      push(@{$contract->{parties}}, $party);

      #natural/non-natural section
      if ($party->{entity_i}) {
        $party->{entity_name} = $m09[1];
      } else {
        $party->{last_name}   = $m09[2];
        $party->{first_name}  = $m09[3] if $m09[3];
        $party->{middle_name} = $m09[4] if $m09[4];
        $party->{prefix}      = $m09[5] if $m09[5];
        $party->{suffix}      = $m09[6] if $m09[6];
      }
      if ($m09[9]) {
        $party->{tax_id}   = $m09[8];
        $party->{tax_id_q} = $m09[9];
      }
      if ($m09[10]) {
        $party->{dob}   = $m09[10];
        $party->{dob}   =~ s/(....)(..)(..)/$1-$2-$3/;
        $party->{dob_q} = $m09[11] if $m09[11];
      }
      if ($m09[14]) {
        $party->{impaired_risk} = $m09[14] eq 'Y' ? 1 : 0;
      }
      #use if instead of while because there's only one record possible
      defined($line = $io->getline) && $record_count++;
      if ( my (@m10) = map{ trim $_} ($line =~ /$R1310/)) {
        $party->{address_line1} = $m10[2];
        $party->{address_line2} = $m10[3] if $m10[3];
        $party->{city}          = $m10[4] if $m10[4];
        $party->{state}         = $m10[5] if $m10[5];
        $party->{zip}           = $m10[6] if $m10[6];
        $party->{country_code}  = $m10[7] if $m10[7];
        defined($line = $io->getline) && $record_count++;
      }
    }
    while ( my (@m11) = map{ trim $_} ($line =~ /$R1311/)) {
      $contract->{service_features} ||= []; #new arrayref if blank
      my $feature = { id_code => $m11[1] };

      $feature->{name}           = $m11[2] if $m11[2];
      $feature->{qty}            = $m11[3] / 100       if $m11[3];
      $feature->{program_type}   = $m11[4] if $m11[4];
      $feature->{start_d}        = $m11[5] if $m11[5];
      $feature->{stop_d}         = $m11[6] if $m11[6];
      $feature->{expense_type}   = $m11[7]             if $m11[7];
      $feature->{expense_dollar} = $m11[8] / 100       if $m11[8];
      $feature->{expense_pct}    = $m11[9] / (10 ** 9) if $m11[9];
      defined($line = $io->getline) && $record_count++;
    }
  }
  my $target = $self->record_count;
  $self->_error("Record and target count mismatch ($record_count : $target)")
    unless $target == $record_count;
  $self->_clear_file_handle;      #close the filehandle
  return \@records;
}

1;
